package myzzyl.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import myzzyl.constants.CommonIntField;
import myzzyl.constants.CommonStatus;
import myzzyl.constants.CommonStrField;
import myzzyl.constants.ErrorConstants;
import myzzyl.domain.dto.SysDeptDto;
import myzzyl.domain.pojo.SysDept;
import myzzyl.domain.pojo.SysUser;
import myzzyl.domain.vo.SysDeptVo;
import myzzyl.domain.vo.TreeItemVo;
import myzzyl.domain.vo.TreeVo;
import myzzyl.exception.BusinessException;
import myzzyl.mapper.SysDeptMapper;
import myzzyl.service.SysDeptService;
import myzzyl.service.SysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author 33249
* @description 针对表【sys_dept(部门表)】的数据库操作Service实现
* @createDate 2025-08-13 15:46:35
*/
@Service
@Slf4j
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept>
    implements SysDeptService {


    @Autowired
    private SysUserService sysUserService;


    /**
     * 获取父级编号下的所有子部门
     * @return 返回值
     */
    @Override
    public List<SysDeptVo> getAll(SysDeptDto sysDeptDto) {
        return baseMapper.selectSysDeptVo(sysDeptDto);
    }

    /**
     * 获取部门详情数据
     * @param id 主键id
     * @return 返回值
     */
    @Override
    public SysDeptVo getInfo(Long id) {
        SysDept sysDept = getById(id);
        if(sysDept == null) {
            throw new BusinessException(ErrorConstants.DEPT_IS_NOT_EXIST);
        }

        return BeanUtil.toBean(sysDept, SysDeptVo.class);
    }


    /**
     * 新增部门
     * @param sysDeptDto 部门表单请求封装类
     * @return 返回值
     */
    @Override
    @Transactional
    public boolean add(SysDeptDto sysDeptDto) {
        // 判断上级部门编号是否为空
        if (StrUtil.isBlank(sysDeptDto.getParentDeptNo())) {
            throw new BusinessException(ErrorConstants.PARENT_DEPT_NO_IS_NULL);
        }
        // 判断部门名称是否为空
        if (StrUtil.isBlank(sysDeptDto.getDeptName())) {
            throw new BusinessException(ErrorConstants.DEPT_NAME_IS_NULL);
        }
        // 判断新增的父级部门编号的层级是否大于四级
        if (StrUtil.count(sysDeptDto.getParentDeptNo(), '.') >= CommonIntField.DEPT_LEVEL_MAX_LIMIT.getNumber() - 1) {
            throw new BusinessException(ErrorConstants.DEPT_LEVEL_IS_OVER);
        }

        // 定义同级最大编号，便于生成当前新增部门编号
        String maxNo = null;

        // 根据上级部门编号查询同级部门
        List<SysDept> deptList = lambdaQuery()
                .eq(SysDept::getParentDeptNo, sysDeptDto.getParentDeptNo()).list();
//                .like(SysDept::getParentDeptNo, sysDeptDto.getParentDeptNo() + "%").list();

        // 遍历同级部门，查询是否有相同的名称，同时计算最大值
        for (SysDept dept : deptList) {
            if (dept.getDeptName().equals(sysDeptDto.getDeptName())) {
                throw new BusinessException(ErrorConstants.DEPT_IS_ALREADY_EXIST);
            }
            // 如果是null或者当前最大编号小于查询出的部门编号就赋值
            if (StrUtil.isBlank(maxNo) || maxNo.compareTo(dept.getDeptNo()) < 0) {
                maxNo = dept.getDeptNo();
            }
        }

        // 生成新的部门编号，规则：01 01.01 01.01.01 01.01.01.01.01
        String newDeptNo;
        if (maxNo == null) {
            // 如果没有同级部门，则生成初始编号
            newDeptNo = sysDeptDto.getParentDeptNo() + ".01";
        } else {
            // 基于最大编号生成新编号
            String suffix = maxNo.substring(maxNo.lastIndexOf(".") + 1);
            int nextNum = Integer.parseInt(suffix) + 1;
            newDeptNo = sysDeptDto.getParentDeptNo() + "." + String.format("%02d", nextNum);
        }

        // 新增SysDept项目
        SysDept sysDept = new SysDept();
        BeanUtils.copyProperties(sysDeptDto, sysDept);
        sysDept.setDataState("0");
        sysDept.setDeptNo(newDeptNo);

        boolean isSuccess = save(sysDept);
        if(isSuccess) {
            // 查询是否有其他部门的负责人是当前新增部门的负责人，有就清空，一个人只能当一个部门的负责人
            lambdaUpdate()
                    .set(SysDept::getLeaderId, null)
                    .eq(SysDept::getLeaderId, sysDept.getLeaderId())
                    .ne(SysDept::getDeptNo, sysDept.getDeptNo())
                    .update();
            return true;
        }

        return false;
    }


    /**
     * 编辑部门
     * @param sysDeptDto 部门表单请求封装类
     * @return 返回值
     */
    @Override
    @Transactional
    public boolean edit(SysDeptDto sysDeptDto) {
        // 判断上级部门编号是否为空
        if (StrUtil.isBlank(sysDeptDto.getParentDeptNo())) {
            throw new BusinessException(ErrorConstants.PARENT_DEPT_NO_IS_NULL);
        }
        // 判断部门名称是否为空
        if (StrUtil.isBlank(sysDeptDto.getDeptName())) {
            throw new BusinessException(ErrorConstants.DEPT_NAME_IS_NULL);
        }
        // 判断上级部门是否是本身（即parentNo等于no）
        if (sysDeptDto.getDeptNo().equals(sysDeptDto.getParentDeptNo())) {
            throw new BusinessException(ErrorConstants.PARENT_DEPT_IS_NOT_SELF);
        }

        // 查询员工是否关联了部门
        if (sysUserService.lambdaQuery().eq(SysUser::getDeptNo, sysDeptDto.getDeptNo()).exists()) {
            throw new BusinessException(ErrorConstants.DEPT_HAS_USER);
        }

        // 根据上级部门编号查询同级部门（从小到大排序）
        List<SysDept> deptList = lambdaQuery()
                .eq(SysDept::getParentDeptNo, sysDeptDto.getParentDeptNo())
                .orderByAsc(SysDept::getDeptNo).list();

        // 循环遍历判断
        deptList.forEach(dept -> {
            // 查询同级下是否已经有了当前要修改的部门名称（除去自己）
            if (!dept.getId().equals(sysDeptDto.getId()) &&
                    dept.getDeptName().equals(sysDeptDto.getDeptName())) {
                throw new BusinessException(ErrorConstants.DEPT_IS_ALREADY_EXIST);
            }
        });

        // 查询数据库中的数据判断父级编号是否发生变化
        SysDept sysDept = getById(sysDeptDto.getId());
        if (sysDept == null) {
            throw new BusinessException(ErrorConstants.DEPT_IS_NOT_EXIST);
        }

        // 发生变化
        if (!sysDept.getParentDeptNo().equals(sysDeptDto.getParentDeptNo())) {
            // 先查询一下当前要修改的部门及其子部门中最大的层级是多少
            int maxLevel = baseMapper.countMaxLevel(sysDept.getDeptNo());
            log.info("最大层级：{}", maxLevel);

            // 计算当前部门所处层级
            String deptNo = sysDept.getDeptNo();
            int currentLevel = deptNo.length() - deptNo.replace(".", "").length();
            log.info("当前层级：{}", currentLevel);

            // 判断最大层级 - 当前层级 + 1 + 要修改的父级部门的层级是否超出最大层级
            if (StrUtil.count(sysDeptDto.getParentDeptNo(), '.') + maxLevel - currentLevel + 1 >=
                    CommonIntField.DEPT_LEVEL_MAX_LIMIT.getNumber()) {
                throw new BusinessException(ErrorConstants.DEPT_LEVEL_IS_OVER);
            }

            // 存储旧值，递归需要
            String oldDeptNo = sysDept.getDeptNo();
            // 基于最大编号生成新编号
            String newDeptNo = null;

            // 先判断同级下是否有部门，没有的话，直接构造即可
            if (CollectionUtil.isEmpty(deptList)) {
                newDeptNo = sysDeptDto.getParentDeptNo() + ".01";
            }else {
                String maxNo = deptList.get(deptList.size() - 1).getDeptNo();
                String suffix = maxNo.substring(maxNo.lastIndexOf(".") + 1);
                int nextNum = Integer.parseInt(suffix) + 1;
                newDeptNo = sysDeptDto.getParentDeptNo() + "." + String.format("%02d", nextNum);
            }

            // 修改当前部门的父级部门和部门编号
            boolean isSuccess = lambdaUpdate()
                    .set(SysDept::getParentDeptNo, sysDeptDto.getParentDeptNo())
                    .set(SysDept::getDeptNo, newDeptNo)
                    .eq(SysDept::getId, sysDeptDto.getId())
                    .update();

            if (isSuccess) {
                // 递归修改子部门的部门编号和父级部门编号
                updateNo(oldDeptNo, newDeptNo);
            }
        }

        // 更新部门
        boolean isSuccess = lambdaUpdate()
                .set(SysDept::getDeptName, sysDeptDto.getDeptName())
                .set(SysDept::getSortNo, sysDeptDto.getSortNo())
                .set(SysDept::getDataState, sysDeptDto.getDataState())
                .set(SysDept::getLeaderId, sysDeptDto.getLeaderId())
                .set(SysDept::getRemark, sysDeptDto.getRemark())
                .eq(SysDept::getId, sysDeptDto.getId())
                .update();

        if (isSuccess) {
            // 查询是否有其他部门的负责人是当前新增部门的负责人，有就清空，一个人只能当一个部门的负责人
            lambdaUpdate()
                .set(SysDept::getLeaderId, null)
                .eq(SysDept::getLeaderId, sysDeptDto.getLeaderId())
                .ne(SysDept::getDeptNo, sysDeptDto.getDeptNo())
                .update();
            return true;
        }

        return false;
    }


    /**
     * 递归修改子部门的部门编号及其父级部门编号
     * @param oldParentDeptNo 父级部门编号的旧值，用于查询子部门
     * @param newParentDeptNo 父级部门编号的旧值，用于构造子部门编号
     */
    private void updateNo(String oldParentDeptNo, String newParentDeptNo) {
        // 根据旧的父级部门编号查询所有子级部门（编号从小到大排列）
        List<SysDept> deptList = lambdaQuery()
                .eq(SysDept::getParentDeptNo, oldParentDeptNo)
                .orderByAsc(SysDept::getDeptNo)
                .list();

        // 递归出口：没有子级部门了
        if (CollectionUtil.isEmpty(deptList)) {
            return;
        }

        // 遍历修改
        for (int i = 0; i < deptList.size(); i++) {
            // 获取当前部门对象
            SysDept dept = deptList.get(i);
            // 存储旧值，递归需要
            String oldDeptNo = dept.getDeptNo();

            // 直接使用新的父级部门编号拼接序号
            String newDeptNo = newParentDeptNo + "." + String.format("%02d", i + 1);
            boolean isSuccess = lambdaUpdate()
                    .set(SysDept::getParentDeptNo, newParentDeptNo)
                    .set(SysDept::getDeptNo, newDeptNo)
                    .eq(SysDept::getId, dept.getId())
                    .update();

            if (!isSuccess) {
                throw new RuntimeException(ErrorConstants.UNKNOWN_ERROR.getMessage());
            }

            // 递归
            updateNo(oldDeptNo, newDeptNo);
        }
    }


    /**
     * 删除部门
     * @param deptNo 部门编号
     * @return 返回值
     */
    @Override
    public boolean remove(String deptNo) {
        // 查询部门是否存在
        SysDept sysDept = lambdaQuery().eq(SysDept::getDeptNo, deptNo).one();
        if (sysDept == null) {
            throw new BusinessException(ErrorConstants.DEPT_IS_NOT_EXIST);
        }

        // 判断部门是否处于启用状态
        if (sysDept.getDataState().equals("0")) {
            throw new BusinessException(ErrorConstants.DEPT_IS_ACTIVE);
        }

        // 员工关联了部门，无法删除
        if (sysUserService.lambdaQuery().eq(SysUser::getDeptNo, deptNo).exists()) {
            throw new BusinessException(ErrorConstants.DEPT_HAS_USER);
        }

        // 查询要删除的部门有无子节点
        List<SysDept> deptList = lambdaQuery()
                .eq(SysDept::getParentDeptNo, sysDept.getDeptNo())
                .list();

        if(CollectionUtil.isEmpty(deptList)) {
            // 没有，直接删除部门
            return baseMapper.deleteById(sysDept.getId()) > 0;
        }else {
            // 有，返回存在子部门，不能删除错误信息
            throw new BusinessException(ErrorConstants.DEPT_HAS_SUB_DEPT);
        }
    }


    /**
     * 启用或禁用部门
     * @param sysDeptDto 部门表单请求封装类
     * @return 返回值
     */
    @Override
    @Transactional
    public boolean enableOrDisableSysDept(SysDeptDto sysDeptDto) {
        // 判断部门编号是否为空
        if (StrUtil.isBlank(sysDeptDto.getDeptNo())) {
            throw new BusinessException(ErrorConstants.DEPT_IS_NOT_EXIST);
        }

        // 判断修改的状态是否为空
        if (StrUtil.isBlank(sysDeptDto.getDataState())) {
            throw new BusinessException(ErrorConstants.DEPT_STATUS_IS_NULL);
        }

        // 判断修改的状态是否为启用
        if (sysDeptDto.getDataState().equals("0")) {
            // 是启用的话，需要判断父级部门是否是禁用状态
            SysDept sysDept = lambdaQuery()
                    .eq(SysDept::getDeptNo, sysDeptDto.getParentDeptNo())
                    .one();
            // 判断是否为空
            if (sysDept == null) {
                throw new BusinessException(ErrorConstants.PARENT_DEPT_IS_NOT_EXIST);
            }
            // 判断状态
            if (sysDept.getDataState().equals("1")) {
                throw new BusinessException(ErrorConstants.PARENT_DEPT_IS_DISABLE);
            }

        }else {
            // 是禁用的话，要判断是否有子部门，有的话需要全部禁用（查询全部子孙节点）
            List<SysDept> deptList = lambdaQuery()
                    .likeRight(SysDept::getParentDeptNo, sysDeptDto.getDeptNo())
                    .list();

            if (CollectionUtil.isNotEmpty(deptList)) {
                // 获取要修改的部门编号集合
                List<String> deptNos = deptList.stream().map(SysDept::getDeptNo).toList();

                // 员工关联了部门，无法禁用
                deptNos.forEach(deptNo -> {
                    if (sysUserService.lambdaQuery().eq(SysUser::getDeptNo, deptNo).exists()) {
                        throw new BusinessException(ErrorConstants.DEPT_HAS_USER);
                    }
                });

                // 批量更新
                lambdaUpdate()
                        .set(SysDept::getDataState, "1")
                        .in(SysDept::getDeptNo, deptNos)
                        .update();
            }
        }
        // 修改状态
        return lambdaUpdate()
                .set(SysDept::getDataState, sysDeptDto.getDataState())
                .eq(SysDept::getDeptNo, sysDeptDto.getDeptNo())
                .update();
    }


    /**
     * 获取所有部门及其子部门
     * @param sysDeptDto 部门表单请求封装类
     * @return 返回值
     */
    @Override
    public TreeVo tree(SysDeptDto sysDeptDto) {
        // 查询没有部门（编号从小到大）
        List<SysDept> deptList = lambdaQuery()
                .orderByAsc(SysDept::getDeptNo)
                .list();

        // 递归构造树形结构结果返回
        TreeItemVo treeItemVo = createTree(deptList.get(0), deptList);
        List<TreeItemVo> treeItemVoList = List.of(treeItemVo);
        return new TreeVo(treeItemVoList);
    }


    /**
     * 递归构造树形结构结果
     * @param currentDept 当前部门
     * @param deptList 全部部门集合
     * @return 返回值
     */
    private TreeItemVo createTree(SysDept currentDept, List<SysDept> deptList) {
        // 构造TreeItemVo返回
        TreeItemVo treeItemVo = new TreeItemVo();
        treeItemVo.setId(currentDept.getDeptNo());
        treeItemVo.setLabel(currentDept.getDeptName());

        // 找出当前部门的子部门
        List<SysDept> sysDeptList = deptList.stream()
                .filter(dept -> dept.getParentDeptNo().equals(currentDept.getDeptNo()))
                .toList();

        log.info("sysDeptList:{}", sysDeptList);

        // 判断子部门是否为空
        if (CollectionUtil.isEmpty(sysDeptList)) {
            // 是的话，直接将当前部门的children属性设置为null
            treeItemVo.setChildren(null);
        }else {
            // 存储当前部门的子部门集合
            List<TreeItemVo> treeItemVoList = new ArrayList<>();

            // 不是，需要遍历所有子部门，并对每个子部门进行递归处理
            for (SysDept dept : sysDeptList) {
                TreeItemVo itemVo = createTree(dept, deptList);
                treeItemVoList.add(itemVo);
            }

            // 设置当前节点的children属性
            treeItemVo.setChildren(treeItemVoList);
        }
        return treeItemVo;
    }

}
